﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

using Twilio.TwilML.BaseTypes;

namespace Twilio.TwilML
{
    [XmlRoot("Response")]
    public class Response
    {
        #region Implicit Type Casting
        public static implicit operator string(Response response)
        {
            return response.ToString();
        }

        public static implicit operator Stream(Response response)
        {
            return response.GetStream();
        }

        public static implicit operator byte[](Response response)
        {
            return response.GetBytes();
        }
        #endregion

        [XmlElement("Say", typeof(Say))]
        [XmlElement("Play", typeof(Play))]
        [XmlElement("Record", typeof(Record))]
        [XmlElement("Gather", typeof(Gather))]
        [XmlElement("Dial", typeof(Dial))]
        [XmlElement("Sms", typeof(Sms))]
        [XmlElement("Hangup", typeof(Hangup))]
        [XmlElement("Redirect", typeof(Redirect))]
        [XmlElement("Reject", typeof(Reject))]
        [XmlElement("Pause", typeof(Pause))]
        public List<BaseTypes.ResponseVerb> Items { get; set; }

        public Response()
        {
            Items = new List<BaseTypes.ResponseVerb>();
        }

        [XmlIgnore]
        public ResponseVerb this[int index]
        {
            get { return Items[index]; }
        }

        public Stream GetStream()
        {
            return GetStream(new UTF8Encoding(false));
        }
        public Stream GetStream(Encoding encoding)
        {
            XmlSerializerNamespaces xmlSerializerNamespaces = new XmlSerializerNamespaces();
            xmlSerializerNamespaces.Add("", "");

            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Response));
            MemoryStream memoryStream = new MemoryStream();
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, encoding);
            xmlTextWriter.Formatting = Formatting.None;
            xmlSerializer.Serialize(xmlTextWriter, this, xmlSerializerNamespaces);

            memoryStream.Seek(0, SeekOrigin.Begin);
            return memoryStream;
        }

        public byte[] GetBytes()
        {
            return GetBytes(new UTF8Encoding(false));
        }
        public byte[] GetBytes(Encoding encoding)
        {
            MemoryStream responseStream = (MemoryStream)GetStream(encoding);
            return responseStream.ToArray();
        }

        public override string ToString()
        {
            MemoryStream responseStream = (MemoryStream)GetStream(new UTF8Encoding(false));
            return Encoding.UTF8.GetString(responseStream.ToArray());
        }

        #region Strongly Typed Append Implementations
        public Say Append(Say say)
        {
            Items.Add(say);
            return say;
        }
        public Play Append(Play play)
        {
            Items.Add(play);
            return play;
        }
        public Record Append(Record record)
        {
            Items.Add(record);
            return record;
        }
        public Gather Append(Gather gather)
        {
            Items.Add(gather);
            return gather;
        }
        public Dial Append(Dial dial)
        {
            Items.Add(dial);
            return dial;
        }
        public Sms Append(Sms sms)
        {
            Items.Add(sms);
            return sms;
        }
        public Hangup Append(Hangup hangup)
        {
            Items.Add(hangup);
            return hangup;
        }
        public Redirect Append(Redirect redirect)
        {
            Items.Add(redirect);
            return redirect;
        }
        public Reject Append(Reject reject)
        {
            Items.Add(reject);
            return reject;
        }
        public Pause Append(Pause pause)
        {
            Items.Add(pause);
            return pause;
        }
        #endregion Strongly Typed Append Implementations

        public static Response Parse(string responseString)
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof(Response));
            return (Response)xmlSerializer.Deserialize(new StringReader(responseString));
        }

        public static bool TryParse(string responseString, out Response response)
        {
            try
            {
                response = Parse(responseString);
                return true;
            }
            catch
            {
                response = null;
                return false;
            }
        }
    }
}
